package cn.cdutetc.library.common;

import cn.cdutetc.library.entity.dto.UserImportDTO;
import cn.cdutetc.library.entity.enums.UserRoleEnum;
import cn.cdutetc.library.entity.enums.UserStatusEnum;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 用户Excel数据解析监听器
 */
@Slf4j
public class UserExcelAnalysisEventListener implements ReadListener<UserImportDTO> {
    
    /**
     * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    
    /**
     * 缓存的数据
     */
    private List<UserImportDTO> cachedDataList = new ArrayList<>(BATCH_COUNT);
    
    /**
     * 错误信息列表
     */
    private List<String> errorMessages = new ArrayList<>();
    
    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context analysis context
     */
    @Override
    public void invoke(UserImportDTO data, AnalysisContext context) {
        log.info("解析到一条数据:{}", data);
        
        // 数据校验
        String errorMsg = validateUserData(data, context.readRowHolder().getRowIndex() + 1);
        if (StringUtils.isNotBlank(errorMsg)) {
            errorMessages.add(errorMsg);
            return;
        }
        
        cachedDataList.add(data);
        
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            // 这里可以进行批量处理，暂时先缓存
            log.info("已缓存{}条数据", cachedDataList.size());
        }
    }
    
    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context analysis context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("所有数据解析完成！共{}条数据", cachedDataList.size());
        if (!errorMessages.isEmpty()) {
            log.warn("数据校验失败，共{}条错误信息", errorMessages.size());
        }
    }
    
    /**
     * 校验用户数据
     * @param data 用户数据
     * @param rowIndex 行号
     * @return 错误信息，为空表示校验通过
     */
    private String validateUserData(UserImportDTO data, int rowIndex) {
        StringBuilder errorMsg = new StringBuilder();
        
        // 必填字段校验
        if (StringUtils.isBlank(data.getUsername())) {
            errorMsg.append("第").append(rowIndex).append("行：用户名不能为空；");
        }
        if (StringUtils.isBlank(data.getPassword())) {
            errorMsg.append("第").append(rowIndex).append("行：密码不能为空；");
        }
        if (StringUtils.isBlank(data.getRealName())) {
            errorMsg.append("第").append(rowIndex).append("行：真实姓名不能为空；");
        }
        if (StringUtils.isBlank(data.getRole())) {
            errorMsg.append("第").append(rowIndex).append("行：角色不能为空；");
        }
        
        // 角色校验
        if (StringUtils.isNotBlank(data.getRole())) {
            UserRoleEnum role = UserRoleEnum.getByCode(data.getRole());
            if (role == null) {
                errorMsg.append("第").append(rowIndex).append("行：角色值无效，应为system_admin/book_admin/normal_user；");
            }
        }
        
        // 状态校验
        if (StringUtils.isNotBlank(data.getStatus())) {
            UserStatusEnum status = UserStatusEnum.getByCode(data.getStatus());
            if (status == null) {
                errorMsg.append("第").append(rowIndex).append("行：状态值无效，应为active/inactive；");
            }
        }
        
        // 用户名长度校验
        if (StringUtils.isNotBlank(data.getUsername()) && (data.getUsername().length() < 3 || data.getUsername().length() > 20)) {
            errorMsg.append("第").append(rowIndex).append("行：用户名长度必须在3-20个字符之间；");
        }
        
        // 密码长度校验
        if (StringUtils.isNotBlank(data.getPassword()) && (data.getPassword().length() < 6 || data.getPassword().length() > 20)) {
            errorMsg.append("第").append(rowIndex).append("行：密码长度必须在6-20个字符之间；");
        }
        
        // 手机号校验
        if (StringUtils.isNotBlank(data.getPhone()) && !data.getPhone().matches("^1[3-9]\\d{9}$")) {
            errorMsg.append("第").append(rowIndex).append("行：手机号格式不正确；");
        }
        
        // 邮箱校验
        if (StringUtils.isNotBlank(data.getEmail()) && !data.getEmail().matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) {
            errorMsg.append("第").append(rowIndex).append("行：邮箱格式不正确；");
        }
        
        return errorMsg.toString();
    }
    
    /**
     * 获取缓存的数据列表
     * @return 数据列表
     */
    public List<UserImportDTO> getCachedDataList() {
        return cachedDataList;
    }
    
    /**
     * 获取错误信息列表
     * @return 错误信息列表
     */
    public List<String> getErrorMessages() {
        return errorMessages;
    }
    
    /**
     * 是否有错误
     * @return 是否有错误
     */
    public boolean hasErrors() {
        return !errorMessages.isEmpty();
    }
}